perm filename MIXIO[MIX,SYS] blob sn#020792 filedate 1972-03-08 generic text, type T, neo UTF8
COMMENT ⊗   VALID 00007 PAGES 
RECORD PAGE   DESCRIPTION
 00001 00001
 00002 00002	 Various I/O button routines  
 00008 00003		"Input-output" operations.
 00013 00004	  The IN instruction  
 00017 00005	  The OUT instruction  
 00023 00006		These are the device specific sections.
 00032 00007		these are the other i/o related operations
 00037 ENDMK
⊗;
COMMENT ⊗ Various I/O button routines  ⊗

QREAD:	SKIPE	CRDBLK				; 0 → NOT INITED
	JRST	QRD1
	INIT	10, 10				; INIT IN IMAGE MORE
	SIXBIT	/DSK/
	CRDBLK+1
	JRST	ZDISK				; ERROR RETURN
	PUSHJ	P,RESCN				;*RES* LOOK FOR NAME ON PREV LINE
	PUSHJ	P,FINFI2			;*RES* LOOK IT UP
	JRST	.+3				;*RES* RESCN SKIPS 2 IF NO ARG
	OUTSTR	[ASCIZ	⊗FILE FOR CARD READER INPUT: ⊗]
	FINFO					; GET FILE DATA
	MOVE	10, [XWD  BLK, CRDBLK+4]	; PUT DATA IN CRDBLK
	BLT	10, CRDBLK+7
	LOOKUP	10, CRDBLK+4			; LOOKUP FILE
	JRST	.-5				; ERROR → TRY AGAIN
	AOS	CRDBLK				; I/0 STATUS WORD ← +1
	JRST	BUTTON
QRD1:	OUTSTR	[ASCIZ ⊗READ FILE ALREADY OPEN⊗]  ;*RES* 
	JRST	QBUTN				;*RES*

QREADX:	RELEAS	10, 0				; CLOSE AND RELEAS CHANNEL
	SETZM	CRDBLK				; RESET I/O STATUS WORD
	JRST	BUTTON


QPUNCH:	SKIPE	CPNBLK				; 0 → NOT INITED
	JRST	QPN1
	INIT	11, 10				; INIT IN IMAGE MORE
	SIXBIT	/DSK/
	XWD	CPNBLK+1, 0
	JRST	ZDISK				; ERROR RETURN
	PUSHJ	P,RESCN				;*RES* LOOK FOR NAME ON PREV LINE
	PUSHJ	P,FINFI2			;*RES* LOOK IT UP
	JRST	.+3				;*RES* RESCN SKIPS 2 IF NO ARG
	OUTSTR	[ASCIZ	⊗FILE FOR CARD PUNCH OUTPUT: ⊗]
	FINFO					; GET FILE DATA
	MOVE	10, [XWD  BLK, CPNBLK+4]	; PUT DATA IN CPNBLK
	BLT	10, CPNBLK+7
	ENTER	11, CPNBLK+4			; ENTER FILE
	JRST	.-5				; ERROR → TRY AGAIN
	AOS	CPNBLK				; I/0 STATUS WORD ← +1
	JRST	BUTTON
QPN1:	OUTSTR	[ASCIZ ⊗PUNCH FILE ALREADY OPEN⊗] ;*RES*
	JRST	QBUTN				;*RES*

QPNCHX:	RELEAS	11, 0				; CLOSE AND RELEAS CHANNEL
	SETZM	CPNBLK				; RESET I/O STATUS WORD
	JRST	BUTTON


QPRINT:	SKIPE	PRNBLK				; 0 → NOT INITED
	JRST	QPR1
	INIT	12, 10				; INIT IN IMAGE MORE
	SIXBIT	/DSK/
	XWD	PRNBLK+1, 0
	JRST	ZDISK				; ERROR RETURN
	PUSHJ	P,RESCN				;*RES* LOOK FOR NAME ON PREV LINE
	PUSHJ	P,FINFI2			;*RES* LOOK IT UP
	JRST	.+3				;*RES* RESCN SKIPS 2 IF NO ARG
	OUTSTR	[ASCIZ	⊗FILE FOR PRINTER OUTPUT: ⊗]
	FINFO					; GET FILE DATA
	MOVE	10, [XWD  BLK, PRNBLK+4]	; PUT DATA IN PRNBLK
	BLT	10, PRNBLK+7
	ENTER	12, PRNBLK+4			; ENTER FILE
	JRST	.-5				; ERROR → TRY AGAIN
	AOS	PRNBLK				; I/0 STATUS WORD ← +1
	JRST	BUTTON
QPR1:	OUTSTR	[ASCIZ ⊗PRINT FILE ALREADY OPEN⊗] ;*RES*
	JRST	QBUTN				;*RES*

QPRNTX:	RELEAS	12, 0				; CLOSE AND RELEAS CHANNEL
	SETZM	PRNBLK				; RESET I/O STATUS WORD
	JRST	BUTTON

QBUTN:	INCHWL	10				;*RES* READ REST OF LINE 
	CAIE	10,12				;*RES*  UP TO THE LF
	JRST	.-2
	JRST	BUTTON				;*RES* THEN GO TO BUTTON

COMMENT	⊗	"Input-output" operations.

	At present (6-25-70), the only devices planned for this MIX
	machine are the following:
		card reader	`CRD'  F=16  chan=10
		card punch	`CPN'  F=17  chan=11
		printer		`PRN'  F=18  chan=12
		typewriter(in)	`TIN'  F=19  chan=13
		typewriter(out)	`TOT'  F=19  chan=14

	The simulation of i/o for CRD, CPN, PRN will be done through the
	use of disk files.

	Each device will have a device block of 8 words, containing
	the following information:
		word   1	an i/o status word
		words  2-4	i/o buffer for the system
		words  5-8	file info for LOOKUP or ENTER

	TIN and TOT will be done directly to and from the teletype.
	In addition, a copy of everything printed on the teletype
	during each use of MIXSIM will be saved on a file called
	MIXTTY.  This will enable the user to obtain hard copies of
	everything.

	⊗

COMMENT	⊗	This subroutine takes the MIX character in register 10
		and puts it into the appropriate place in MIXBUF (using
		a byte pointer in 11).  If this fills MIXBUF, the routine
		moves MIXBUF to the address in MIXAD, increments MIXAD,
		resets the byte pointer in 11, and zeros out MIXBUF.
			Called by "CTOMIX"
	⊗

OPDEF	CTOMIX	[PUSHJ  P, .]
	IDPB	10, 11				; PUT BYTE INTO MIXBUF
	TLNE	11, 770000			; LAST BYTE IN MIXBUF?
	POPJ	P,				; NO → RETURN
	MOVE	10, MIXBUF			; YES → PUT INTO MIX CORE
	MOVEM	10, @MIXAD
	AOS	MIXAD				; INCREMENT MIXAD
	MOVE	11, [POINT  6, MIXBUF, 5]	; RESET BYTE POINTER
	SETZM	MIXBUF				; ZERO OUT MIXBUF
	POPJ	P,				; RETURN

COMMENT	⊗	This subroutine takes the MIX word in register 10
		and moves it to the address in MIXAD.
			Called by "WTOMIX"
	⊗

OPDEF	WTOMIX	[PUSHJ	P, .]
	MOVEM	10, @MIXAD			; PUT INTO MIX CORE
	AOS	MIXAD				; INCREMENT MIXAD
	POPJ	P,				; RETURN


COMMENT	⊗	This subroutine is similar to CTOMIX, but instead of
		putting the characters into MIXBUF, it takes them out
		(resetting MIXBUF and MIXAD when necessary).
			Called by "CFRMIX"
	⊗

OPDEF	CFRMIX	[PUSHJ  P, .]
	TLNE	11, 770000			; LAST BYTE IN MIXBUF?
	JRST	.+5				; NO
	MOVE	10, @MIXAD			; YES → GET NEXT ONE
	MOVEM	10, MIXBUF
	AOS	MIXAD				; INCREMENT MIXAD
	MOVE	11, [POINT  6, MIXBUF, 5]	; RESET POINTER
	ILDB	10, 11				; GET NEXT CHARACTER
	POPJ	P,				; RETURN

COMMENT	⊗	This is similarly analagous to WTOMIX.
			Called by "WFRMIX"
	⊗

OPDEF	WFRMIX	[PUSHJ  P, .]
	MOVE	10, @MIXAD			; GET NEXT WORD
	AOS	MIXAD				; INCREMENT MIXAD
	POPJ	P,				; RETURN







COMMENT ⊗  The IN instruction  ⊗

IN:	MOVE	12,MSPEC			; GET MEMORY SPECIFICATIONS
	ADDI	12, MC0000			; RELOCATE SO ADDRESSES MIX-CORE
	MOVEM	12, MIXAD			; INITIALIZE MIXAD
	LDB	11, [POINT 6, INSTR, 29]	; GET FIELD-BYTE
	CAILE	11, =19				; UNIT NUMBER MUST BE ≤19
	JRST	ZUNIT				; ERROR
	SKIPG	13, UNIN(11)			; 13 ← CHANNEL NUMBER AND
	JRST	ZUNIT				;	ERROR IF ZERO
	HLRZ	10, LOCK1(11)		; first we wait for this device to finish anything
	JUMPE	10, .+4			; no input on this device
	MOVE	10, (10)		; get time for finishing input
	CAMLE	10, EXTIME		; has it happened?
	MOVEM	10, EXTIME		; no → make it happen
	HRRZ	10, LOCK1(11)
	JUMPE	10, .+4			; no output on this device
	MOVE	10, (10)		; get time for finishing output
	CAMLE	10, EXTIME		; has it happened?
	MOVEM	10, EXTIME		; now it has
	HRLZ	10, 12			; now see if any interlocks on the range to work with
	HRR	10, LOCK0(11)
	ADD	10, 12
	SUB	10, [XWD MC0000, MC0000]
	MOVEM	10, MLOCK		; now MLOCK has range descriptor
	WWLOCK				; test whether it's OK to use this range
	JRST	ZWLOCK			; no it isn't
	LDB	11, [POINT 6, INSTR, 29]
	HLRZ	10, LOCK1(11)			; add device to RLOCKT for read-interlock
	JUMPE	10, IN1				; zero → this device doesn't get entered (should never take this jump)
	MOVEM	10, LOCK2			; save base address of entry in table
	HLRZ	10, LOCK0(11)			; this gives total interlock time
	ADD	10, EXTIME			; so this is time when device is finally ready
	MOVEM	10, @LOCK2			; a fact we should remember
	AOS	LOCK2				; for next part of table entry
	MOVE	10, MIXAD			; this is base address of locked-out range
	SUBI	10, MC0000			; make it relative to MC0000
	MOVEM	10, @LOCK2			; and remember it
	AOS	LOCK2				; get ready for next part of entry
	ADD	10, LOCK0(11)			; this gives final address of range
	HRRZS	10				; get rid of garbage in left half
	MOVEM	10, @LOCK2			; and remember this too
IN1:	MOVE	11, [POINT  6, MIXBUF, 5]	; INITIALIZE BYTE POINTER TO MIXBUF
	SETZM	MIXBUF				; ZERO OUT MIXBUF
	JRST	@INAD(13)			; GO TO APPROPRIATE ADDRESS

INAD:	0
	0
	0
	0
	0
	0
	0
	0
	INCRD
	0
	0
	INTIN
	0
	0
	0
	0


COMMENT ⊗  The OUT instruction  ⊗

OUT:	MOVE	12,MSPEC			; GET MEMORY SPECIFICATIONS
	ADDI	12, MC0000			; RELOCATE SO ADDRESSES MIX-CORE
	MOVEM	12, MIXAD			; INITIALIZE MIXAD
	LDB	11, [POINT 6, INSTR, 29]	; GET FIELD-BYTE
	CAILE	11, =19				; UNIT NUMBER MUST BE ≤19
	JRST	ZUNIT				; ERROR
	SKIPG	13, UNOUT(11)			; 13 ← CHANNEL NUMBER AND
	JRST	ZUNIT				;	ERROR IF ZERO
	HLRZ	10, LOCK1(11)		; first we wait for this device to finish anything
	JUMPE	10, .+4			; no input on this device
	MOVE	10, (10)		; get time for finishing input
	CAMLE	10, EXTIME		; has it happened?
	MOVEM	10, EXTIME		; no → make it happen
	HRRZ	10, LOCK1(11)
	JUMPE	10, .+4			; no output on this device
	MOVE	10, (10)		; get time for finishing output
	CAMLE	10, EXTIME		; has it happened?
	MOVEM	10, EXTIME		; now it has
	HRLZ	10, 12			; now see if any interlocks on the range to work with
	HRR	10, LOCK0(11)
	ADD	10, 12
	SUB	10, [XWD MC0000, MC0000]
	MOVEM	10, MLOCK		; now MLOCK has range descriptor
	RRLOCK				; test whether it's OK to use this range
	JRST	ZRLOCK			; no it isn't
	LDB	11, [POINT 6, INSTR, 29]
	HRRZ	10, LOCK1(11)			; add device to RLOCKT for read-interlock
	JUMPE	10, OUT1				; zero → this device doesn't get entered (should never take this jump)
	MOVEM	10, LOCK2			; save base address of entry in table
	HLRZ	10, LOCK0(11)			; this gives total interlock time
	ADD	10, EXTIME			; so this is time when device is finally ready
	MOVEM	10, @LOCK2			; a fact we should remember
	AOS	LOCK2				; for next part of table entry
	MOVE	10, MIXAD			; this is base address of locked-out range
	SUBI	10, MC0000			; make it relative to MC0000
	MOVEM	10, @LOCK2			; and remember it
	AOS	LOCK2				; get ready for next part of entry
	ADD	10, LOCK0(11)			; this gives final address of range
	HRRZS	10				; get rid of garbage in left half
	MOVEM	10, @LOCK2			; and remember this too
OUT1:	MOVE	11, [POINT  6, MIXBUF, 5]	; INITIALIZE BYTE POINTER TO MIXBUF
	SETZM	MIXBUF				; ZERO OUT MIXBUF
	JRST	@OUTAD(13)			; GO TO APPROPRIATE ADDRESS

OUTAD:	0
	0
	0
	0
	0
	0
	0
	0
	0
	OUTCPN
	OUTPRN
	0
	OUTTOT
	0
	0
	0


COMMENT	⊗	These tables are used to convert the F unit number
		to i/o channels.  A `0' indicates that that form of
		i/o cannot be done with that unit.
	⊗

UNIN:	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	10	; CARD READER
	0	; CARD PUNCH CANNOT DO INPUT
	0	; PRINTER CANNTO DO INPUT
	13	; TYPEWRITER

UNOUT:	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0	; CARD READER CANNOT DO OUTPUT
	11	; CARD PUNCH
	12	; PRINTER
	14	; TYPEWRITER



MIXAD:	0		; CONTAINS ADDRESS OF NEXT MIX WORD TO WORRY ABOUT
MIXBUF:	0		; BUFFER FOR MIX WORDS
IOBUF:	0		; BUFFER FOR I/O DEVICES
COUNT:	0



LOCK0:	repeat =16	{0}			; this table has interlock times and record lengths
	XWD	=1000, =15			; CRD: 1000u and 16 words
	XWD	=1000, =15			; CPN: 1000u and 16 words
	XWD	=750, =23			; PRN:  750u and 24 words
	XWD	=2000, =13			; TIN,TOT: 2000u and 14 words

LOCK1:	repeat =16	{0}			; this table has address for interlock tables
	XWD	CRDLOK, 0			; CRD: read-interlock
	XWD	0, CPNLOK			; CPN: write-interlock
	XWD	0, PRNLOK			; PRN: write-interlock
	XWD	TINLOK, TOTLOK			; Typ: both read and write

LOCK2:	0					; this is just used for temporary stoarage
COMMENT	⊗	These are the device specific sections.
	⊗



; ******	CARD READER
CRDBLK:	BLOCK	10

INCRD:	SKIPN	CRDBLK				; I/O STATUS WORD = 0
	JRST	ZIOBEG				;	→ NOT INITED YET
	PUSHJ	P, GETWRD			; GET INPUT WORD
	TRNN	10, 1				; IS IT AN SOS LINE-NUMBER?
	JRST	.+3				; NO
	PUSHJ	P, GETWRD			; YES → GET NEXT WORD
	IBP	12				;	AND SKIP <TAB>
	MOVEI	10, =80				; SET UP COUNTER FOR CHARACTERS
	MOVEM	10, COUNT
	TLNN	12, 760000			; LAST BYTE IN 13?
	PUSHJ	P, GETWRD			; YES → GET NEXT WRD
	ILDB	10, 12				; GET NEXT ASCII CHARACTER
	CAIN	10, 15				; CARRIAGE-RETURN →
	JRST	.+6				;	FINISH LINE WITH BLANKS
	MOVE	10, ASCMIX(10)			; CONVERT TO MIX CODE
	CTOMIX
	SOSE	COUNT				; BACK FOR MORE
	JRST	.-10
	JRST	.+5				; NOW GO TO END OF LINE
	SETZ	10,				; MIX CODE FOR <BLANK> IS 00
	CTOMIX
	SOSE	COUNT				; BACK FOR MORE
	JRST	.-3
	TLNN	12, 760000			; LAST BYTE IN 13?
	PUSHJ	P, GETWRD			; YES → GET NEXT WORD
	ILDB	10, 12				; GET NEXT ASCII CHARACTER
	CAIE	10, 12				; KEEP TRYING UNTIL LINE-FEED
	JRST	.-4
	SETZM	CRDBLK				; I/O STATUS WORD ← -1
	SOS	CRDBLK
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER

GETWRD:	SOSG	CRDBLK+3			; DECREMENT CHARACTER COUNT
	IN	10,				; COUNT EXHAUSTED, NEXT BUFFER
	JRST	.+4				; OK, SO CONTINUE
	STATZ	10, 20000			; TEST WHETHER ERROR WAS EOF
	JRST	ZEOF				; YES
	JRST	ZINOUT				; SOME OTHER I/O ERROR
	ILDB	10, CRDBLK+2			; GET INPUT WORD
	JUMPE	10,GETWRD			;*RES* IGNORE NULLS AT END OF RECORD
	MOVEM	10, IOBUF			; PUT INTO IOBUF
	MOVE	12, [POINT  7, IOBUF]		; INITIALIZE BYTE POINTER
	POPJ	P,				; RETURN



	; ******	CARD PUNCH
CPNBLK:	BLOCK	10

OUTCPN:	SKIPN	CPNBLK				; I/O STATUS WORD = 0
	JRST	ZIOBEG				;	→ NOT INITED YET
	MOVEI	10, =80				; SET UP COUNTER FOR CHARS
	MOVEM	10, COUNT
	SETZM	IOBUF				; ZERO OUT IOBUF
	MOVE	12, [POINT  7, IOBUF]		; INITIALIZE BYTE POINTER
	SETZ	11,				; FIX 11 SO CFRMIX WORKS FIRST TIME
	CFRMIX
	MOVE	10, MIXASC(10)			; CONVERT TO ASCII CODE
	IDPB	10, 12				; PUT INTO IOBUF
	TLNN	12, 760000			; LAST BYTE IN IOBUF?
	PUSHJ	P, PUTWRD			; YES → OUTPUT IT
	SOSE	COUNT				; BACK FOR MORE
	JRST	.-6
	MOVEI	10, 15				; NOW OUTPUT C-R, L-F
	IDPB	10, 12
	MOVEI	10, 12
	IDPB	10, 12
	PUSHJ	P, PUTWRD
	SETZM	CPNBLK				; I/O STATUS WORD ← -1
	SOS	CPNBLK
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER

PUTWRD:	SOSG	CPNBLK+3			; DECREMENT CHARACTER COUNT
	OUT	11,				; OUTPUT THIS BUFFER
	SKIPA					; SUCCESS
	JRST	ZINOUT				; ERROR
	MOVE	10, IOBUF			; GET OUTPUT WORD
	IDPB	10, CPNBLK+2			; PUT ONTO FILE
	SETZM	IOBUF				; ZERO OUT IOBUF
	MOVE	12, [POINT  7, IOBUF]		; INITIALIZE BYTE POINTER
	POPJ	P,				; RETURN



; ******	TYPEWRITER (IN)
TINBLK:	BLOCK	10

INTIN:	MOVEI	10, =70				; SET UP COUNTER
	MOVEM	10, COUNT
	INCHWL	10				; GET FIRST CHAR OF LINE
	SKIPA					; FOR FIRST TIME
	INCHRW	10				; GET NEXT CHAR
	CAIN	10, 15				; CARRIAGE-RETURN →
	JRST	.+6				;	FINISH LINE WITH BLANKS
	MOVE	10, ASCMIX(10)			; CONVERT TO MIX CODE
	CTOMIX
	SOSE	COUNT				; BACK FOR MORE
	JRST	.-6
	JRST	.+5				; NOW GO TO END OF LINE
	SETZ	10,				; MIX CODE FOR <BLANK> IS 00
	CTOMIX
	SOSE	COUNT				; BACK FOR MORE
	JRST	.-3
	INCHRW	10				; KEEP TRYING UNTIL LINE-FEED
	CAIE	10, 12
	JRST	.-2
	SETZM	TINBLK				; I/O STATUS WORD ← -1
	SOS	TINBLK
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER



	; ******	TYPEWRITER (OUT)
TOTBLK:	BLOCK	10

OUTTOT:	MOVEI	10, =70				; SET UP COUNTER FOR CHARS
	MOVEM	10, COUNT
	SETZ	11,				; FIX 11 SO CFRMIX WORKS FIRST TIME
	CFRMIX
	MOVE	10, MIXASC(10)			; CONVERT TO ASCII CODE
	OUTCHR	10				; OUTPUT IT
	SOSE	COUNT				; BACK FOR MORE
	JRST	.-4
	MOVEI	10, 15				; NOW OUTPUT C-R, L-F
	OUTCHR	10
	MOVEI	10, 12
	OUTCHR	10
	SETZM	TOTBLK				; I/O STATUS WORD ← -1
	SOS	TOTBLK
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER



	; ******	PRINTER
PRNBLK:	BLOCK	10

OUTPRN:	SKIPN	PRNBLK				; I/O STATUS WORD = 0
	JRST	ZIOBEG				;	→ NOT INITED YET
	MOVEI	10, =120			; SET UP COUNTER FOR CHARS
	MOVEM	10, COUNT
	SETZM	IOBUF				; ZERO OUT IOBUF
	MOVE	12, [POINT  7, IOBUF]		; INITIALIZE BYTE POINTER
	SETZ	11,				; FIX 11 SO CFRMIX WORKS FIRST TIME
	CFRMIX
	MOVE	10, MIXASC(10)			; CONVERT TO ASCII CODE
	IDPB	10, 12				; PUT INTO IOBUF
	TLNN	12, 760000			; LAST BYTE IN IOBUF?
	PUSHJ	P, PRNWRD			; YES → OUTPUT IT
	SOSE	COUNT				; BACK FOR MORE
	JRST	.-6
	MOVEI	10, 15				; NOW OUTPUT C-R, L-F
	IDPB	10, 12
	SKIPN	NOJECT				;*RES* SEE IF PRINT OVER PERF
	JRST	.+6				;*RES* NO
	MOVEI	10,177				;*RES* 
	IDPB	10,12				;*RES* LPT LIKES 177&21 FOR LF ALSO
	MOVEI	10,21				;*RES* 
	IDPB	10,12				;*RES* 
	JRST	.+3				;*RES* 
	MOVEI	10, 12
	IDPB	10, 12
	PUSHJ	P, PRNWRD
	SETZM	PRNBLK				; I/O STATUS WORD ← -1
	SOS	PRNBLK
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER

PRNWRD:	SOSG	PRNBLK+3			; DECREMENT CHARACTER COUNT
	OUT	12,				; OUTPUT THIS BUFFER
	SKIPA					; SUCCESS
	JRST	ZINOUT				; ERROR
	MOVE	10, IOBUF			; GET OUTPUT WORD
	IDPB	10, PRNBLK+2			; PUT ONTO FILE
	SETZM	IOBUF				; ZERO OUT IOBUF
	MOVE	12, [POINT  7, IOBUF]		; INITIALIZE BYTE POINTER
	POPJ	P,				; RETURN




COMMENT	⊗	these are the other i/o related operations
	⊗



IOC:	MOVE	12,MSPEC		; the only one we'll allow is IOC 0,(18)
	JUMPN	12, ZIOC		; so if M in non-zero, it's an error
	LDB	11, [POINT 6, INSTR, 29]	; now get F-field
	CAIE	11, =18			; if F 18?
	JRST	ZIOC			; no → error
	MOVE	10, PRNLOK		; wait until printer is finished
	CAMLE	10, EXTIME		; do this by changing EXTIME if necessary
	MOVEM	10, EXTIME		; it is necessary
	MOVE	10, EXTIME		; now we must interlock the printer for the form-feed
	ADDI	10, =1000		; we will use 1000u
	MOVEM	10, PRNLOK		; establish interlock time
	SETOM	PRNLOK+1		; use range -1:-1
	SETOM	PRNLOK+2
	MOVEI	10, 6430		;*RES* this is a carriage-return, form-feed
	MOVEM	10, IOBUF		; so this is <null><null><null><c-r><f-f>
	SKIPN	PRNBLK			; is printer inited?
	JRST	ZIOBEG			; no → txis is an error
	PUSHJ	P,PRNWRD		;*RES* now send the new page stuff
	SETOM	PRNBLK			; i/o status word ← -1
	JRST	MIXMON			; and return to instruction interpreter



JBUS:	MOVE	12,MSPEC		; first we see whether it is JBUS *
	CAMN	12, ISPEC		; does it match address of present instruction
	JRST	JBUS1			; yes → special case
	MOVSI	10, (<CAMGE 10,>)	; no → use same routine as JRED
	JRST	JRB
JBUS1:	LDB	11, [POINT 6, INSTR, 29]	; get F-field
	CAIL	11, =16			; is it a legal unit?
	CAILE	11, =19
	JRST	ZDEV			; no → error
	MOVE	10, EXTIME		; save EXTIME so we get a count of number of executions
	MOVEM	10, JBUSX
	HLRZ	10, LOCK1(11)		; get address to check for input busy
	JUMPE	10, .+4			; no such address → don't check
	MOVE	10, (10)		; get time when device is finished
	CAML	10, EXTIME		; and see whether it has happened
	MOVEM	10, EXTIME		; no → change so it has
	HRRZ	10, LOCK1(11)		; address to check for output busy
	JUMPE	10, .+4			; no address → don't check
	MOVE	10, (10)		; get time device is finished
	CAML	10, EXTIME		; and see whether time has come pass
	MOVEM	10, EXTIME		; no → now it has
	MOVE	10, EXTIME		; calculate number of executions
	SUBM	10, JBUSX		; new EXTIME - old EXTIME
	SKIPG	JBUSX			; any at all?
	SETZM	JBUSX			; no → make sure it's zero
	JRST	MIXMON			; so device is no longer busy



JRED:	MOVSI	10, (<CAML 10,>)	; so we can use same routine for JBUS, JRED

JRB:	HLLM	10, JRB1		; fix so we do the right compares
	HLLM	10, JRB2
	MOVE	12,MSPEC		; get address to jump to
	TESTM				; is is valid?
	LDB	11, [POINT 6, INSTR, 29]	; get F-field
	CAIL	11, =16			; is it valid?
	CAILE	11, =19
	JRST	ZDEV			; no → error
	HLRZ	10, LOCK1(11)		; test for input busy
	JUMPE	10, .+4			; no input
	MOVE	10, (10)		; get execution time for finishing
JRB1:		EXTIME			; this is the crucial compare
	JRST	MIXMON			; don't want to jump
	HRRZ	10, LOCK1(11)		; test for output busy
	JUMPE	10, .+4
	MOVE	10, (10)
JRB2:		EXTIME			; another crucial compare
	JRST	MIXMON			; don't want to jump
	JRST	JMP			; we do want to jump



JBUSX:	0				; this will contain the number of executions of JBUS *